#include "shapeeditor.h"
#include "ui_shapeeditor.h"
#include <QInputDialog>
#include <QMessageBox>

ShapeEditor::ShapeEditor(QWidget *parent) : QWidget(parent),
    ui(new Ui::ShapeEditor)
{
    ui->setupUi(this);
    ui->buttonDraw->hide();

    _loadingObject  = false;
    _loadingFixture = false;
    _drawing        = false;
    _drawingShape   = 0;
    _object         = 0;

    connect(ui->shapeType, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeShapeType()));
    connect(ui->buttonDraw, SIGNAL(clicked()), this, SLOT(StartDrawing()));
    connect(ui->view, SIGNAL(Clicked(QPoint)), this, SLOT(DrawingEvent(QPoint)));

    connect(ui->addFixture,          SIGNAL(clicked()),                    this, SLOT(AddFixture()));
    connect(ui->deleteFixture,       SIGNAL(clicked()),                    this, SLOT(DeleteFixture()));
    connect(ui->fixtureList,         SIGNAL(currentIndexChanged(QString)), this, SLOT(SelectFixture(QString)));
    connect(ui->addTexture,          SIGNAL(clicked()),                    this, SLOT(AddTexture()));
    connect(ui->deleteTexture,       SIGNAL(clicked()),                    this, SLOT(DeleteTexture()));
    connect(ui->objectTextureList,   SIGNAL(currentRowChanged(int)),       this, SLOT(SelectTexture()));
    connect(ui->addAnimation,        SIGNAL(clicked()),                    this, SLOT(AddAnimation()));
    connect(ui->deleteAnimation,     SIGNAL(clicked()),                    this, SLOT(DeleteAnimation()));
    connect(ui->objectAnimationList, SIGNAL(currentRowChanged(int)),       this, SLOT(SelectAnimation()));

    // Object auto-save
    connect(ui->isBullet,         SIGNAL(stateChanged(int)),        this, SLOT(SaveObject()));
    connect(ui->hasFixedRotation, SIGNAL(stateChanged(int)),        this, SLOT(SaveObject()));
    connect(ui->objectType,       SIGNAL(currentIndexChanged(int)), this, SLOT(SaveObject()));

    // Shape auto-save
    connect(ui->shapeType, SIGNAL(currentIndexChanged(int)), this, SLOT(SaveFixture()));
    connect(ui->density,   SIGNAL(valueChanged(int)),        this, SLOT(SaveFixture()));
    connect(ui->friction,  SIGNAL(valueChanged(int)),        this, SLOT(SaveFixture()));
    connect(ui->isSensor,  SIGNAL(stateChanged(int)),        this, SLOT(SaveFixture()));
    connect(ui->collisionGroup, SIGNAL(currentIndexChanged(int)), this, SLOT(SaveFixture()));

    connect(ui->positionX, SIGNAL(valueChanged(int)), this, SLOT(UpdateShape()));
    connect(ui->positionY, SIGNAL(valueChanged(int)), this, SLOT(UpdateShape()));
    connect(ui->width,     SIGNAL(valueChanged(int)), this, SLOT(UpdateShape()));
    connect(ui->height,    SIGNAL(valueChanged(int)), this, SLOT(UpdateShape()));
    connect(ui->radius,    SIGNAL(valueChanged(int)), this, SLOT(UpdateShape()));
    connect(ui->angle,     SIGNAL(valueChanged(int)), this, SLOT(UpdateShape()));

    // Icons
    QIcon iconBoxShape("icons/shape-box.png");
    QIcon iconCircleShape("icons/shape-circle.png");
    QIcon iconPolygonShape("icons/shape-polygon.png");
    QIcon iconAddTexture("icons/add-texture.png");
    QIcon iconAdd("icons/list-add.png");

    ui->shapeType->setItemIcon(0, iconBoxShape);
    ui->shapeType->setItemIcon(1, iconCircleShape);
    ui->shapeType->setItemIcon(2, iconPolygonShape);
    ui->addTexture->setIcon(iconAddTexture);
    ui->addAnimation->setIcon(iconAddTexture);
    ui->addFixture->setIcon(iconAdd);

    FixtureFormShowCircle(false);
    FixtureFormShowPolygon(false);
    FixtureFormShowBox(true);
}

void ShapeEditor::FixtureFormShowBox(bool is)
{
    ui->labelPosX->setVisible(is);
    ui->labelPosY->setVisible(is);
    ui->labelWidth->setVisible(is);
    ui->labelHeight->setVisible(is);
    ui->positionX->setVisible(is);
    ui->positionY->setVisible(is);
    ui->width->setVisible(is);
    ui->height->setVisible(is);
}

void ShapeEditor::FixtureFormShowCircle(bool is)
{
    ui->labelPosX->setVisible(is);
    ui->labelPosY->setVisible(is);
    ui->positionX->setVisible(is);
    ui->positionY->setVisible(is);
    ui->labelRadius->setVisible(is);
    ui->radius->setVisible(is);
}

void ShapeEditor::FixtureFormShowPolygon(bool is)
{
    ui->buttonDraw->setVisible(is);
}

ShapeEditor::~ShapeEditor()
{
    delete ui;
}

void ShapeEditor::ChangeShapeType()
{
    FixtureFormShowBox(false);
    FixtureFormShowCircle(false);
    FixtureFormShowPolygon(false);
    switch (ui->shapeType->currentIndex())
    {
    case 0:
        _shape->type = "box";
        FixtureFormShowBox(true);
        break ;
    case 1:
        _shape->type = "circle";
        FixtureFormShowCircle(true);
        break ;
    case 2:
        _shape->type = "polygon";
        FixtureFormShowPolygon(true);
        break ;
    }
    LoadShape(*_shape);
}

void ShapeEditor::UpdateShape()
{
    if (!_drawingShape)
      return ;
    sf::Vector2f position;

    position.x = ui->positionX->value();
    position.y = ui->positionY->value();
    _drawingShape->SetPosition(position);
    switch (ui->shapeType->currentIndex())
    {
    case 0: // Box
      {
        sf::RectangleShape* shape = reinterpret_cast<sf::RectangleShape*>(_drawingShape);
        sf::Vector2f        size;

        size.x = ui->width->value();
        size.y = ui->height->value();
        shape->SetSize(size);
        shape->SetRotation(ui->angle->value());
        break ;
      }
    case 1: // Circle
      {
        sf::CircleShape* shape = reinterpret_cast<sf::CircleShape*>(_drawingShape);
        shape->SetRadius(ui->radius->value());
        break ;
      }
    }
    SaveFixture();
}

void ShapeEditor::StartDrawing()
{
    _drawing = true;
    _shape->vertices.clear();
    ((sf::ConvexShape*)_drawingShape)->SetPointCount(0);
    _vertices.clear();
}

void ShapeEditor::StopDrawing()
{
    _drawing = false;
}

void ShapeEditor::DrawingEvent(QPoint pos)
{
    if (_drawing && _shape)
    {
        sf::Vector2f point(pos.x(), pos.y());

        ((sf::ConvexShape*)_drawingShape)->SetPointCount(((sf::ConvexShape*)_drawingShape)->GetPointCount() + 1);
        ((sf::ConvexShape*)_drawingShape)->SetPoint(((sf::ConvexShape*)_drawingShape)->GetPointCount() - 1, point);
        _shape->vertices << point;
    }
}

void                  ShapeEditor::AddFixture()
{
    QString name = QInputDialog::getText(this, "Fixture name", "Nom de la forme :");

    if (name != "")
    {
        ObjectManager::Shape shape;

        shape.name = name;
        _object->fixtures.push_back(shape);
        ui->fixtureList->addItem(name);
        ui->fixtureList->setCurrentIndex(ui->fixtureList->count() - 1);
        LoadFixture(_object->fixtures.last());
    }
}

void                  ShapeEditor::DeleteFixture()
{
    int res = QMessageBox::warning(this, "Suppression de forme", "Etes-vous sur de vouloir supprimer " + _shape->name + " ?", QMessageBox::Yes, QMessageBox::No);

    if (res == QMessageBox::Yes)
    {
      QList<ObjectManager::Shape>::iterator current = _object->fixtures.begin();
      QList<ObjectManager::Shape>::iterator end     = _object->fixtures.end();

      for (; current != end ; ++current)
      {
        if ((*current).name == ui->fixtureList->currentText())
        {
          _object->fixtures.erase(current);
          break ;
        }
      }
      ui->view->ClearShapes();
      ui->fixtureEditor->setEnabled(false);
      if (_drawingShape)
        delete _drawingShape;
      _shape        = 0;
      _drawingShape = 0;
      ui->fixtureList->removeItem(ui->fixtureList->currentIndex());
    }
}

void                  ShapeEditor::SelectFixture(QString name)
{
    QList<ObjectManager::Shape>::iterator current = _object->fixtures.begin();
    QList<ObjectManager::Shape>::iterator end     = _object->fixtures.end();

    ui->deleteFixture->setEnabled(false);
    for (; current != end ; ++current)
    {
        if ((*current).name == name)
        {
            LoadFixture(*current);
            ui->deleteFixture->setEnabled(true);
            break ;
        }
    }
}

void                  ShapeEditor::SaveFixture()
{
    if (_loadingFixture)
      return ;
    switch (ui->shapeType->currentIndex())
    {
    case 0:
        _shape->type   = "box";
        _shape->size.x = ui->width->value();
        _shape->size.y = ui->height->value();
        _shape->angle  = ui->angle->value();
        break ;
    case 1:
        _shape->type   = "circle";
        _shape->size.x = ui->radius->value();
        break ;
    case 2:
        _shape->type   = "polygon";
        break ;
    }
    _shape->position.x     = ui->positionX->value();
    _shape->position.y     = ui->positionY->value();
    _shape->density        = ui->density->value();
    _shape->friction       = ui->friction->value();
    _shape->collisionGroup = ui->collisionGroup->currentText();
    _shape->sensor         = ui->isSensor->isChecked();
}

void                  ShapeEditor::LoadShape(ObjectManager::Shape& shape)
{
    if (_drawingShape)
    {
        ui->view->ClearShapes();
        delete _drawingShape;
    }
    if (shape.type == "box")
    {
      sf::RectangleShape* sfshape = new sf::RectangleShape(shape.size);

      sfshape->SetPosition(shape.position);
      sfshape->SetRotation(shape.angle);
      _drawingShape = sfshape;
    }
    else if (shape.type == "circle")
    {
      sf::CircleShape* sfshape = new sf::CircleShape(shape.size.x);

      sfshape->SetPosition(shape.position);
      _drawingShape = sfshape;
    }
    else if (shape.type == "polygon")
    {
      sf::ConvexShape* sfshape = new sf::ConvexShape;
      unsigned int     i       = 0;

      sfshape->SetPointCount(shape.vertices.count());
      foreach (sf::Vector2f vertice, shape.vertices)
        sfshape->SetPoint(i++, vertice);
      _drawingShape = sfshape;
    }
    _drawingShape->SetFillColor(sf::Color::Transparent);
    _drawingShape->SetOutlineColor(sf::Color::Red);
    _drawingShape->SetOutlineThickness(2.f);
    ui->view->AddShape(_drawingShape);
}

void                  ShapeEditor::LoadFixture(ObjectManager::Shape& shape)
{
    // Loading Fixture
    _loadingFixture = true;
    _shape          = &shape;
    if (shape.type == "box")
      ui->shapeType->setCurrentIndex(0);
    else if (shape.type == "circle")
      ui->shapeType->setCurrentIndex(1);
    else if (shape.type == "polygon")
      ui->shapeType->setCurrentIndex(2);
    ui->angle->setValue(shape.angle);
    ui->width->setValue(shape.size.x);
    ui->height->setValue(shape.size.y);
    ui->radius->setValue(shape.size.x);
    ui->positionX->setValue(shape.position.x);
    ui->positionY->setValue(shape.position.y);
    ui->density->setValue(shape.density);
    ui->friction->setValue(shape.friction);
    ui->isSensor->setChecked(shape.sensor);
    if (shape.collisionGroup == "")
	ui->collisionGroup->setCurrentIndex(0);
    else
    {
	int i = ui->collisionGroup->findText(shape.collisionGroup, Qt::MatchExactly);
	ui->collisionGroup->setCurrentIndex(i > 0 ? i : 0);
    }
    ui->fixtureEditor->setEnabled(true);
    LoadShape(shape);
    _loadingFixture = false;
}

void                  ShapeEditor::LoadObject(ObjectManager::Object* object)
{
    _loadingObject = true;
    _object        = object;
    _shape         = 0;
    _drawingShape  = 0;

    ui->objectTextureList->clear();
    ui->objectAnimationList->clear();
    ui->fixtureList->clear();
    ui->fixtureEditor->setEnabled(false);
    ui->deleteFixture->setEnabled(false);
    ui->fixtureEditor->setEnabled(false);

    foreach (ObjectManager::Shape shape, object->fixtures)
      ui->fixtureList->addItem(shape.name);
    if (ui->fixtureList->count())
    {
      _shape = &(object->fixtures.first());
      ui->fixtureList->setCurrentIndex(0);
      LoadFixture(object->fixtures.first());
    }

    ui->hasFixedRotation->setChecked(object->hasFixedRotation);
    ui->isBullet->setChecked(object->isBullet);
    if (object->type == "dynamic")
      ui->objectType->setCurrentIndex(0);
    else if (object->type == "kinematic")
      ui->objectType->setCurrentIndex(1);
    else if (object->type == "static")
      ui->objectType->setCurrentIndex(2);
    foreach (QString texName, object->textures)
      ui->objectTextureList->addItem(texName);
    foreach (QString animName, object->animations)
      ui->objectAnimationList->addItem(animName);
    if (object->animations.count())
      ui->objectAnimationList->setCurrentRow(0);
    if (object->textures.count())
      ui->objectTextureList->setCurrentRow(0);
    _loadingObject = false;
}

void ShapeEditor::SaveObject()
{
    if (_loadingObject)
      return ;
    _object->textures.clear();
    _object->animations.clear();
    foreach (QListWidgetItem* item, ui->objectTextureList->findItems("*", Qt::MatchWildcard))
      _object->textures   << item->text();
    foreach (QListWidgetItem* item, ui->objectAnimationList->findItems("*", Qt::MatchWildcard))
      _object->animations << item->text();
    _object->hasFixedRotation = ui->hasFixedRotation->isChecked();
    _object->isBullet         = ui->isBullet->isChecked();
    switch (ui->objectType->currentIndex())
    {
    case 0:
        _object->type = "dynamic";
        break ;
    case 1:
        _object->type = "kinematic";
        break ;
    case 2:
        _object->type = "static";
        break ;
    }
}

void ShapeEditor::NewTexture(QString texture)
{
    ui->worldTextureList->addItem(texture);
    ui->addTexture->setEnabled(true);
}

void ShapeEditor::NewAnimation(QString animation)
{
    ui->worldAnimationList->addItem(animation);
    ui->addAnimation->setEnabled(true);
}

void ShapeEditor::TextureDeleted(QString name)
{
    int i = 0;

    while (i < ui->worldTextureList->count())
    {
	if (ui->worldTextureList->itemText(i) == name)
	{
	    ui->worldTextureList->removeItem(i);
	    break ;
	}
	++i;
    }
}

void ShapeEditor::AnimationDeleted(QString name)
{
    int i = 0;

    while (i < ui->worldAnimationList->count())
    {
	if (ui->worldAnimationList->itemText(i) == name)
	{
	    ui->worldAnimationList->removeItem(i);
	    break ;
	}
	++i;
    }
}

void ShapeEditor::NewCollisionGroup(QString name)
{
    ui->collisionGroup->addItem(name);
}

void ShapeEditor::DeletedCollisionGroup(QString name)
{
    int i = ui->collisionGroup->findText(name, Qt::MatchExactly);
    ui->collisionGroup->removeItem(i);
}

void ShapeEditor::Reset(void)
{
    ui->worldTextureList->clear();
    ui->worldAnimationList->clear();
    ui->addTexture->setEnabled(false);
    ui->addAnimation->setEnabled(false);
}

void ShapeEditor::AddTexture()
{
  QString            texName = ui->worldTextureList->currentText();

  ui->objectTextureList->addItem(texName);
  SaveObject();
}

void ShapeEditor::AddAnimation()
{
  QString            animName = ui->worldAnimationList->currentText();

  ui->objectAnimationList->addItem(animName);
  SaveObject();
}

void ShapeEditor::SelectTexture()
{
  QListWidgetItem* item = ui->objectTextureList->currentItem();

  if (item)
  {
      QString texName = item->text();
      const sf::Texture* texture = _textureManager->GetByName(texName);

      if (texture)
	ui->view->SetTexture(*texture);
  }
}

void ShapeEditor::SelectAnimation()
{
  QListWidgetItem* item = ui->objectAnimationList->currentItem();

  if (item)
  {
      QString                                animName = item->text();
      const Shiny::SpriteAnimate::Animation* anim = _animationManager->GetByName(animName);
      Shiny::SpriteAnimate::AnimationArray   array;

      if (anim)
      {
          array.push_back(*anim);
          ui->view->GetSpriteAnimate().SetAnimations(array);
          ui->view->GetSpriteAnimate().SetAnimation(0);
      }
  }
}

void ShapeEditor::DeleteTexture()
{
  QListWidgetItem* item = ui->objectTextureList->currentItem();

  if (item)
  {
      ui->objectTextureList->removeItemWidget(item);
      delete item;
      SaveObject();
  }
}

void ShapeEditor::DeleteAnimation()
{
    QListWidgetItem* item = ui->objectAnimationList->currentItem();

    if (item)
    {
	ui->objectAnimationList->removeItemWidget(item);
	delete item;
	SaveObject();
    }
}
